Implement essential color cycling feature
authorHavoc Pennington <hp@redhat.com>
Wed, 15 Nov 2000 23:25:08 +0000 (23:25 +0000)
committerHavoc Pennington <hp@src.gnome.org>
Wed, 15 Nov 2000 23:25:08 +0000 (23:25 +0000)
2000-11-15  Havoc Pennington  <hp@redhat.com>

* gtk/testtext.c: Implement essential color cycling feature

ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
gtk/testtext.c
tests/testtext.c

index fe681ed215f2ec8209d2dc4a7b572f222f435164..fda558b50fc23fc4f0a62c18e65f0acae1386994 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2000-11-15  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/testtext.c: Implement essential color cycling feature
+
 2000-11-15  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtktextview.c (changed_handler): Invalidate the side windows
index fe681ed215f2ec8209d2dc4a7b572f222f435164..fda558b50fc23fc4f0a62c18e65f0acae1386994 100644 (file)
@@ -1,3 +1,7 @@
+2000-11-15  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/testtext.c: Implement essential color cycling feature
+
 2000-11-15  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtktextview.c (changed_handler): Invalidate the side windows
index fe681ed215f2ec8209d2dc4a7b572f222f435164..fda558b50fc23fc4f0a62c18e65f0acae1386994 100644 (file)
@@ -1,3 +1,7 @@
+2000-11-15  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/testtext.c: Implement essential color cycling feature
+
 2000-11-15  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtktextview.c (changed_handler): Invalidate the side windows
index fe681ed215f2ec8209d2dc4a7b572f222f435164..fda558b50fc23fc4f0a62c18e65f0acae1386994 100644 (file)
@@ -1,3 +1,7 @@
+2000-11-15  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/testtext.c: Implement essential color cycling feature
+
 2000-11-15  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtktextview.c (changed_handler): Invalidate the side windows
index fe681ed215f2ec8209d2dc4a7b572f222f435164..fda558b50fc23fc4f0a62c18e65f0acae1386994 100644 (file)
@@ -1,3 +1,7 @@
+2000-11-15  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/testtext.c: Implement essential color cycling feature
+
 2000-11-15  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtktextview.c (changed_handler): Invalidate the side windows
index fe681ed215f2ec8209d2dc4a7b572f222f435164..fda558b50fc23fc4f0a62c18e65f0acae1386994 100644 (file)
@@ -1,3 +1,7 @@
+2000-11-15  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/testtext.c: Implement essential color cycling feature
+
 2000-11-15  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtktextview.c (changed_handler): Invalidate the side windows
index fe681ed215f2ec8209d2dc4a7b572f222f435164..fda558b50fc23fc4f0a62c18e65f0acae1386994 100644 (file)
@@ -1,3 +1,7 @@
+2000-11-15  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/testtext.c: Implement essential color cycling feature
+
 2000-11-15  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtktextview.c (changed_handler): Invalidate the side windows
index ec2c5a1a5f1ef1aabd47d17886fa093b9405b6f9..e8a6e42f0114fa0feb216ac70610a3f4fa79d2ff 100644 (file)
@@ -24,6 +24,9 @@ struct _Buffer
   GtkTextTag *not_editable_tag;
   GtkTextTag *found_text_tag;
   GtkTextTag *custom_tabs_tag;
+  GSList *color_tags;
+  guint color_cycle_timeout;
+  gdouble start_hue;
 };
 
 struct _View
@@ -51,6 +54,9 @@ static void     buffer_search_forward (Buffer *buffer,
 static void     buffer_search_backward (Buffer *buffer,
                                        const char *str,
                                        View *view);
+static void     buffer_set_colors      (Buffer  *buffer,
+                                        gboolean enabled);
+static void     buffer_cycle_colors    (Buffer  *buffer);
 
 static View *view_from_widget (GtkWidget *widget);
 
@@ -905,6 +911,16 @@ do_cursor_visible_changed (gpointer callback_data,
   gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), callback_action);
 }
 
+static void
+do_color_cycle_changed (gpointer callback_data,
+                        guint callback_action,
+                        GtkWidget *widget)
+{
+  View *view = view_from_widget (widget);
+
+  buffer_set_colors (view->buffer, callback_action);
+}
+
 static void
 do_apply_editable (gpointer callback_data,
                    guint callback_action,
@@ -986,6 +1002,69 @@ do_apply_tabs (gpointer callback_data,
     }
 }
 
+static void
+do_apply_colors (gpointer callback_data,
+                 guint callback_action,
+                 GtkWidget *widget)
+{
+  View *view = view_from_widget (widget);
+  Buffer *buffer = view->buffer;
+  GtkTextIter start;
+  GtkTextIter end;
+  
+  if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
+                                            &start, &end))
+    {
+      if (!callback_action)
+        {
+          GSList *tmp;
+          
+          tmp = buffer->color_tags;
+          while (tmp != NULL)
+            {
+              gtk_text_buffer_remove_tag (view->buffer->buffer,
+                                          tmp->data,
+                                          &start, &end);              
+              tmp = g_slist_next (tmp);
+            }
+        }
+      else
+        {
+          GSList *tmp;
+          
+          tmp = buffer->color_tags;
+          while (TRUE)
+            {
+              GtkTextIter next;
+              gboolean done = FALSE;
+              
+              next = start;
+              gtk_text_iter_next_char (&next);
+              gtk_text_iter_next_char (&next);
+
+              if (gtk_text_iter_compare (&next, &end) > 0)
+                {
+                  next = end;
+                  done = TRUE;
+                }
+              
+              gtk_text_buffer_apply_tag (view->buffer->buffer,
+                                         tmp->data,
+                                         &start, &next);
+
+              start = next;
+
+              if (done)
+                return;
+              
+              tmp = g_slist_next (tmp);
+              if (tmp == NULL)
+                tmp = buffer->color_tags;
+            } 
+        }
+    }
+}
+
 enum
 {
   RESPONSE_FORWARD,
@@ -1142,6 +1221,9 @@ static GtkItemFactoryEntry menu_items[] =
   { "/Settings/sep1",        NULL,      0,                0, "<Separator>" },
   { "/Settings/Sane spacing", NULL,    do_spacing_changed,  FALSE, "<RadioItem>" },
   { "/Settings/Funky spacing", NULL,    do_spacing_changed,  TRUE, "/Settings/Sane spacing" },
+  { "/Settings/sep1",        NULL,      0,                0, "<Separator>" },
+  { "/Settings/Don't cycle color tags", NULL,    do_color_cycle_changed,  FALSE, "<RadioItem>" },
+  { "/Settings/Cycle colors", NULL,    do_color_cycle_changed,  TRUE, "/Settings/Don't cycle color tags" },
   { "/_Attributes",      NULL,         0,                0, "<Branch>" },
   { "/Attributes/Editable",      NULL,         do_apply_editable, TRUE, NULL },
   { "/Attributes/Not editable",          NULL,         do_apply_editable, FALSE, NULL },
@@ -1149,6 +1231,8 @@ static GtkItemFactoryEntry menu_items[] =
   { "/Attributes/Visible",       NULL,         do_apply_invisible, TRUE, NULL },
   { "/Attributes/Custom tabs",           NULL,         do_apply_tabs, FALSE, NULL },
   { "/Attributes/Default tabs",          NULL,         do_apply_tabs, TRUE, NULL },
+  { "/Attributes/Color cycles",          NULL,         do_apply_colors, TRUE, NULL },
+  { "/Attributes/No colors",                     NULL,         do_apply_colors, FALSE, NULL },
   { "/_Test",           NULL,         0,           0, "<Branch>" },
   { "/Test/_Example",           NULL,         do_example,  0, NULL },
 };
@@ -1298,11 +1382,14 @@ check_buffer_saved (Buffer *buffer)
     return TRUE;
 }
 
+#define N_COLORS 16
+
 static Buffer *
 create_buffer (void)
 {
   Buffer *buffer;
   PangoTabArray *tabs;
+  gint i;
   
   buffer = g_new (Buffer, 1);
 
@@ -1312,6 +1399,22 @@ create_buffer (void)
   buffer->filename = NULL;
   buffer->untitled_serial = -1;
 
+  buffer->color_tags = NULL;
+  buffer->color_cycle_timeout = 0;
+  buffer->start_hue = 0.0;
+  
+  i = 0;
+  while (i < N_COLORS)
+    {
+      GtkTextTag *tag;
+
+      tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
+      
+      buffer->color_tags = g_slist_prepend (buffer->color_tags, tag);
+      
+      ++i;
+    }
+  
   buffer->invisible_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
   gtk_object_set (GTK_OBJECT (buffer->invisible_tag),
                   "invisible", TRUE,
@@ -1480,6 +1583,7 @@ buffer_unref (Buffer *buffer)
   buffer->refcount--;
   if (buffer->refcount == 0)
     {
+      buffer_set_colors (buffer, FALSE);
       buffers = g_slist_remove (buffers, buffer);
       gtk_object_unref (GTK_OBJECT (buffer->buffer));
       g_free (buffer->filename);
@@ -1487,6 +1591,176 @@ buffer_unref (Buffer *buffer)
     }
 }
 
+static void
+hsv_to_rgb (gdouble *h,
+           gdouble *s,
+           gdouble *v)
+{
+  gdouble hue, saturation, value;
+  gdouble f, p, q, t;
+
+  if (*s == 0.0)
+    {
+      *h = *v;
+      *s = *v;
+      *v = *v; /* heh */
+    }
+  else
+    {
+      hue = *h * 6.0;
+      saturation = *s;
+      value = *v;
+      
+      if (hue >= 6.0)
+       hue = 0.0;
+      
+      f = hue - (int) hue;
+      p = value * (1.0 - saturation);
+      q = value * (1.0 - saturation * f);
+      t = value * (1.0 - saturation * (1.0 - f));
+      
+      switch ((int) hue)
+       {
+       case 0:
+         *h = value;
+         *s = t;
+         *v = p;
+         break;
+         
+       case 1:
+         *h = q;
+         *s = value;
+         *v = p;
+         break;
+         
+       case 2:
+         *h = p;
+         *s = value;
+         *v = t;
+         break;
+         
+       case 3:
+         *h = p;
+         *s = q;
+         *v = value;
+         break;
+         
+       case 4:
+         *h = t;
+         *s = p;
+         *v = value;
+         break;
+         
+       case 5:
+         *h = value;
+         *s = p;
+         *v = q;
+         break;
+         
+       default:
+         g_assert_not_reached ();
+       }
+    }
+}
+
+static void
+hue_to_color (gdouble   hue,
+              GdkColor *color)
+{
+  gdouble h, s, v;
+
+  h = hue;
+  s = 1.0;
+  v = 1.0;
+
+  g_return_if_fail (hue <= 1.0);
+  
+  hsv_to_rgb (&h, &s, &v);
+
+  color->red = h * 65535;
+  color->green = s * 65535;
+  color->blue = v * 65535;
+}
+
+
+static gint
+color_cycle_timeout (gpointer data)
+{
+  Buffer *buffer = data;
+
+  buffer_cycle_colors (buffer);
+
+  return TRUE;
+}
+
+static void
+buffer_set_colors (Buffer  *buffer,
+                   gboolean enabled)
+{
+  GSList *tmp;
+  gdouble hue = 0.0;
+
+  if (enabled && buffer->color_cycle_timeout == 0)
+    buffer->color_cycle_timeout = gtk_timeout_add (500, color_cycle_timeout, buffer);
+  else if (!enabled && buffer->color_cycle_timeout != 0)
+    {
+      gtk_timeout_remove (buffer->color_cycle_timeout);
+      buffer->color_cycle_timeout = 0;
+    }
+    
+  tmp = buffer->color_tags;
+  while (tmp != NULL)
+    {
+      if (enabled)
+        {
+          GdkColor color;
+          
+          hue_to_color (hue, &color);
+
+          gtk_object_set (GTK_OBJECT (tmp->data),
+                          "foreground_gdk", &color,
+                          NULL);
+        }
+      else
+        gtk_object_set (GTK_OBJECT (tmp->data),
+                        "foreground_set", FALSE,
+                        NULL);
+
+      hue += 1.0 / N_COLORS;
+      
+      tmp = g_slist_next (tmp);
+    }
+}
+
+static void
+buffer_cycle_colors (Buffer *buffer)
+{
+  GSList *tmp;
+  gdouble hue = buffer->start_hue;
+  
+  tmp = buffer->color_tags;
+  while (tmp != NULL)
+    {
+      GdkColor color;
+      
+      hue_to_color (hue, &color);
+      
+      gtk_object_set (GTK_OBJECT (tmp->data),
+                      "foreground_gdk", &color,
+                      NULL);
+
+      hue += 1.0 / N_COLORS;
+      if (hue > 1.0)
+        hue = 0.0;
+      
+      tmp = g_slist_next (tmp);
+    }
+
+  buffer->start_hue += 1.0 / N_COLORS;
+  if (buffer->start_hue > 1.0)
+    buffer->start_hue = 0.0;
+}
+
 static void
 close_view (View *view)
 {
index ec2c5a1a5f1ef1aabd47d17886fa093b9405b6f9..e8a6e42f0114fa0feb216ac70610a3f4fa79d2ff 100644 (file)
@@ -24,6 +24,9 @@ struct _Buffer
   GtkTextTag *not_editable_tag;
   GtkTextTag *found_text_tag;
   GtkTextTag *custom_tabs_tag;
+  GSList *color_tags;
+  guint color_cycle_timeout;
+  gdouble start_hue;
 };
 
 struct _View
@@ -51,6 +54,9 @@ static void     buffer_search_forward (Buffer *buffer,
 static void     buffer_search_backward (Buffer *buffer,
                                        const char *str,
                                        View *view);
+static void     buffer_set_colors      (Buffer  *buffer,
+                                        gboolean enabled);
+static void     buffer_cycle_colors    (Buffer  *buffer);
 
 static View *view_from_widget (GtkWidget *widget);
 
@@ -905,6 +911,16 @@ do_cursor_visible_changed (gpointer callback_data,
   gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), callback_action);
 }
 
+static void
+do_color_cycle_changed (gpointer callback_data,
+                        guint callback_action,
+                        GtkWidget *widget)
+{
+  View *view = view_from_widget (widget);
+
+  buffer_set_colors (view->buffer, callback_action);
+}
+
 static void
 do_apply_editable (gpointer callback_data,
                    guint callback_action,
@@ -986,6 +1002,69 @@ do_apply_tabs (gpointer callback_data,
     }
 }
 
+static void
+do_apply_colors (gpointer callback_data,
+                 guint callback_action,
+                 GtkWidget *widget)
+{
+  View *view = view_from_widget (widget);
+  Buffer *buffer = view->buffer;
+  GtkTextIter start;
+  GtkTextIter end;
+  
+  if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
+                                            &start, &end))
+    {
+      if (!callback_action)
+        {
+          GSList *tmp;
+          
+          tmp = buffer->color_tags;
+          while (tmp != NULL)
+            {
+              gtk_text_buffer_remove_tag (view->buffer->buffer,
+                                          tmp->data,
+                                          &start, &end);              
+              tmp = g_slist_next (tmp);
+            }
+        }
+      else
+        {
+          GSList *tmp;
+          
+          tmp = buffer->color_tags;
+          while (TRUE)
+            {
+              GtkTextIter next;
+              gboolean done = FALSE;
+              
+              next = start;
+              gtk_text_iter_next_char (&next);
+              gtk_text_iter_next_char (&next);
+
+              if (gtk_text_iter_compare (&next, &end) > 0)
+                {
+                  next = end;
+                  done = TRUE;
+                }
+              
+              gtk_text_buffer_apply_tag (view->buffer->buffer,
+                                         tmp->data,
+                                         &start, &next);
+
+              start = next;
+
+              if (done)
+                return;
+              
+              tmp = g_slist_next (tmp);
+              if (tmp == NULL)
+                tmp = buffer->color_tags;
+            } 
+        }
+    }
+}
+
 enum
 {
   RESPONSE_FORWARD,
@@ -1142,6 +1221,9 @@ static GtkItemFactoryEntry menu_items[] =
   { "/Settings/sep1",        NULL,      0,                0, "<Separator>" },
   { "/Settings/Sane spacing", NULL,    do_spacing_changed,  FALSE, "<RadioItem>" },
   { "/Settings/Funky spacing", NULL,    do_spacing_changed,  TRUE, "/Settings/Sane spacing" },
+  { "/Settings/sep1",        NULL,      0,                0, "<Separator>" },
+  { "/Settings/Don't cycle color tags", NULL,    do_color_cycle_changed,  FALSE, "<RadioItem>" },
+  { "/Settings/Cycle colors", NULL,    do_color_cycle_changed,  TRUE, "/Settings/Don't cycle color tags" },
   { "/_Attributes",      NULL,         0,                0, "<Branch>" },
   { "/Attributes/Editable",      NULL,         do_apply_editable, TRUE, NULL },
   { "/Attributes/Not editable",          NULL,         do_apply_editable, FALSE, NULL },
@@ -1149,6 +1231,8 @@ static GtkItemFactoryEntry menu_items[] =
   { "/Attributes/Visible",       NULL,         do_apply_invisible, TRUE, NULL },
   { "/Attributes/Custom tabs",           NULL,         do_apply_tabs, FALSE, NULL },
   { "/Attributes/Default tabs",          NULL,         do_apply_tabs, TRUE, NULL },
+  { "/Attributes/Color cycles",          NULL,         do_apply_colors, TRUE, NULL },
+  { "/Attributes/No colors",                     NULL,         do_apply_colors, FALSE, NULL },
   { "/_Test",           NULL,         0,           0, "<Branch>" },
   { "/Test/_Example",           NULL,         do_example,  0, NULL },
 };
@@ -1298,11 +1382,14 @@ check_buffer_saved (Buffer *buffer)
     return TRUE;
 }
 
+#define N_COLORS 16
+
 static Buffer *
 create_buffer (void)
 {
   Buffer *buffer;
   PangoTabArray *tabs;
+  gint i;
   
   buffer = g_new (Buffer, 1);
 
@@ -1312,6 +1399,22 @@ create_buffer (void)
   buffer->filename = NULL;
   buffer->untitled_serial = -1;
 
+  buffer->color_tags = NULL;
+  buffer->color_cycle_timeout = 0;
+  buffer->start_hue = 0.0;
+  
+  i = 0;
+  while (i < N_COLORS)
+    {
+      GtkTextTag *tag;
+
+      tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
+      
+      buffer->color_tags = g_slist_prepend (buffer->color_tags, tag);
+      
+      ++i;
+    }
+  
   buffer->invisible_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL);
   gtk_object_set (GTK_OBJECT (buffer->invisible_tag),
                   "invisible", TRUE,
@@ -1480,6 +1583,7 @@ buffer_unref (Buffer *buffer)
   buffer->refcount--;
   if (buffer->refcount == 0)
     {
+      buffer_set_colors (buffer, FALSE);
       buffers = g_slist_remove (buffers, buffer);
       gtk_object_unref (GTK_OBJECT (buffer->buffer));
       g_free (buffer->filename);
@@ -1487,6 +1591,176 @@ buffer_unref (Buffer *buffer)
     }
 }
 
+static void
+hsv_to_rgb (gdouble *h,
+           gdouble *s,
+           gdouble *v)
+{
+  gdouble hue, saturation, value;
+  gdouble f, p, q, t;
+
+  if (*s == 0.0)
+    {
+      *h = *v;
+      *s = *v;
+      *v = *v; /* heh */
+    }
+  else
+    {
+      hue = *h * 6.0;
+      saturation = *s;
+      value = *v;
+      
+      if (hue >= 6.0)
+       hue = 0.0;
+      
+      f = hue - (int) hue;
+      p = value * (1.0 - saturation);
+      q = value * (1.0 - saturation * f);
+      t = value * (1.0 - saturation * (1.0 - f));
+      
+      switch ((int) hue)
+       {
+       case 0:
+         *h = value;
+         *s = t;
+         *v = p;
+         break;
+         
+       case 1:
+         *h = q;
+         *s = value;
+         *v = p;
+         break;
+         
+       case 2:
+         *h = p;
+         *s = value;
+         *v = t;
+         break;
+         
+       case 3:
+         *h = p;
+         *s = q;
+         *v = value;
+         break;
+         
+       case 4:
+         *h = t;
+         *s = p;
+         *v = value;
+         break;
+         
+       case 5:
+         *h = value;
+         *s = p;
+         *v = q;
+         break;
+         
+       default:
+         g_assert_not_reached ();
+       }
+    }
+}
+
+static void
+hue_to_color (gdouble   hue,
+              GdkColor *color)
+{
+  gdouble h, s, v;
+
+  h = hue;
+  s = 1.0;
+  v = 1.0;
+
+  g_return_if_fail (hue <= 1.0);
+  
+  hsv_to_rgb (&h, &s, &v);
+
+  color->red = h * 65535;
+  color->green = s * 65535;
+  color->blue = v * 65535;
+}
+
+
+static gint
+color_cycle_timeout (gpointer data)
+{
+  Buffer *buffer = data;
+
+  buffer_cycle_colors (buffer);
+
+  return TRUE;
+}
+
+static void
+buffer_set_colors (Buffer  *buffer,
+                   gboolean enabled)
+{
+  GSList *tmp;
+  gdouble hue = 0.0;
+
+  if (enabled && buffer->color_cycle_timeout == 0)
+    buffer->color_cycle_timeout = gtk_timeout_add (500, color_cycle_timeout, buffer);
+  else if (!enabled && buffer->color_cycle_timeout != 0)
+    {
+      gtk_timeout_remove (buffer->color_cycle_timeout);
+      buffer->color_cycle_timeout = 0;
+    }
+    
+  tmp = buffer->color_tags;
+  while (tmp != NULL)
+    {
+      if (enabled)
+        {
+          GdkColor color;
+          
+          hue_to_color (hue, &color);
+
+          gtk_object_set (GTK_OBJECT (tmp->data),
+                          "foreground_gdk", &color,
+                          NULL);
+        }
+      else
+        gtk_object_set (GTK_OBJECT (tmp->data),
+                        "foreground_set", FALSE,
+                        NULL);
+
+      hue += 1.0 / N_COLORS;
+      
+      tmp = g_slist_next (tmp);
+    }
+}
+
+static void
+buffer_cycle_colors (Buffer *buffer)
+{
+  GSList *tmp;
+  gdouble hue = buffer->start_hue;
+  
+  tmp = buffer->color_tags;
+  while (tmp != NULL)
+    {
+      GdkColor color;
+      
+      hue_to_color (hue, &color);
+      
+      gtk_object_set (GTK_OBJECT (tmp->data),
+                      "foreground_gdk", &color,
+                      NULL);
+
+      hue += 1.0 / N_COLORS;
+      if (hue > 1.0)
+        hue = 0.0;
+      
+      tmp = g_slist_next (tmp);
+    }
+
+  buffer->start_hue += 1.0 / N_COLORS;
+  if (buffer->start_hue > 1.0)
+    buffer->start_hue = 0.0;
+}
+
 static void
 close_view (View *view)
 {